package com.cougil.uoc.seghismed.cipher;

import iaik.utils.Base64OutputStream;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;

import org.apache.log4j.Logger;
import org.jdom.DocType;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;

/**
 * Classe que permet encapsular la lògica relacionada amb carregar i emmagatzemar
 * informació amb fitxers amb format XML, incloent-hi la signatura d'aquesta
 *
 * @author Ignacio Cougil Jares
 * @author <a href="mailto:jcastellar@uoc.edu">Jordi Castella-Roca</a>
 */
public class XMLManager {

	private static final Logger logger = Logger.getLogger(SignerManager.class);

	// Element amb el document base en si: Document

	private Element comment;

	private Element data;
	private Element document;
	private String fileName;
	private Element root;

	private Element signature;
	private String strComment;
	private String strData;

	private String strSignature;
	private String strTitle;
	private Element title;

	public XMLManager(String file) {
		this.fileName = new String(file);

		this.root = new Element("SignedDocument");

		this.document = new Element("Document");
		this.signature = new Element("Signature");

		this.title = new Element("Title");
		this.comment = new Element("Comment");
		this.data = new Element("Data");

		this.root.addContent(this.document);
		this.root.addContent(this.signature);

		this.document.addContent(this.title);
		this.document.addContent(this.comment);
		this.document.addContent(this.data);
	}

	public void doFinal() throws IOException {
		FileOutputStream fileOut = new FileOutputStream(this.fileName);

		// Nou
		Document finalDoc = new Document(this.root);
		finalDoc.setDocType(new DocType("SignedDocument"));

		XMLOutputter xmlout = new XMLOutputter();

		// Nou
		xmlout.output(finalDoc, fileOut);
		fileOut.close();
	}

	public void doInit() throws JDOMException, IOException {
		SAXBuilder parser = new SAXBuilder();

		URL urlResource = this.getClass().getResource(this.fileName);
		FileInputStream fileIn = new FileInputStream(urlResource.getFile());

		Document xmldoc = parser.build(fileIn);
		// nou
		// xmldoc.setDocType(new
		// DocType("SignedDocument","./signature.dtd"));

		this.root = xmldoc.getRootElement();
		this.document = this.root.getChild("Document");
		this.signature = this.root.getChild("Signature");
		this.data = this.document.getChild("Data");
		this.title = this.document.getChild("Title");
		this.comment = this.document.getChild("Comment");

		this.strData = this.data.getText();
		this.strComment = this.comment.getText();
		this.strTitle = this.title.getText();

		this.strSignature = this.signature.getText();
	}

	public String getData() {
		return this.strData;
	}

	private String getDataFromFile(String fileName) throws IOException {
		ByteArrayOutputStream bAOS = new ByteArrayOutputStream();
		Base64OutputStream toB64 = new Base64OutputStream(bAOS);

		//SeghismedUtils.showClassAbsolutePath(this.getClass());
		URL urlResource = this.getClass().getResource(fileName);
		// truc per aconseguir obtenir els fitxers si aquests estan referenciats de forma
		// absoluta en el fitxer de recursos
		if (urlResource == null) {
			urlResource = new URL(fileName);
		}
		FileInputStream fileIn = new FileInputStream(urlResource.getFile());

		int len;

		byte[] buffer = new byte[1000];

		while (-1 != (len = fileIn.read(buffer, 0, buffer.length))) {
			toB64.write(buffer, 0, len);
		}

		toB64.flush();
		toB64.close();
		fileIn.close();

		return new String(bAOS.toByteArray());

	}

	public String getDataToSign() throws IOException, JDOMException {
		ByteArrayOutputStream outByteArray = null;

		XMLOutputter xmloutOne = new XMLOutputter();
		ByteArrayOutputStream os = new ByteArrayOutputStream();
		xmloutOne.output(this.root, os);

		ByteArrayInputStream kk = new ByteArrayInputStream(os.toByteArray());
		SAXBuilder parser = new SAXBuilder();
		Document xmldoc = parser.build(kk);

		Element rootTS = xmldoc.getRootElement();
		this.document = rootTS.getChild("Document");

		XMLOutputter xmlout = new XMLOutputter();
		outByteArray = new ByteArrayOutputStream();
		xmlout.output(this.document, outByteArray);

		return new String(outByteArray.toByteArray());
	}

	public String getSignature() {
		return this.strSignature;
	}

	public void lookat() {
		XMLManager.logger.debug("Data: " + getData() + " Signature: " + getSignature());
	}

	public void readDataFromFile(String file) throws IOException {
		this.data.addContent( getDataFromFile(file) );
	}

	public void setComment(String commentNew) {
		this.strComment = new String(commentNew);
		this.comment.addContent(this.strComment);
	}

	public void setSignature(byte[] p7) throws IOException {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		Base64OutputStream base64os = new Base64OutputStream(out);
		base64os.write(p7, 0, p7.length);
		base64os.flush();
		base64os.close();
		this.strSignature = new String(out.toByteArray());
		this.signature.addContent(this.strSignature);
	}

	public void setTitle(String titleNew) {
		this.strTitle = new String(titleNew);
		this.title.addContent(this.strTitle);
	}

}
